package log

import (
	"encoding/json"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"sync"
)

var (
	logger *zap.Logger
	once   sync.Once
)

var rawJSON = []byte(`
{
  "level": "debug",
  "encoding": "json",
  "outputPaths": [
    "stdout"
  ],
  "errorOutputPaths": [
    "stderr"
  ],
  "initialFields": {
    "foo": "bar"
  },
  "encoderConfig": {
    "messageKey": "message",
    "levelKey": "level",
    "levelEncoder": "lowercase"
  }
}
`)

func Logger() *zap.Logger {
	return logger
}

func init() {
	once.Do(func() {
		var err error
		//rawJSON, err := ioutil.ReadFile("./config.json")
		//if err != nil {
		//	panic(err)
		//}
		var cfg zap.Config
		if err = json.Unmarshal(rawJSON, &cfg); err != nil {
			panic(err)
		}
		logger, err = cfg.Build()
		if err != nil {
			panic(err)
		}
		defer logger.Sync()
		logger.Info("install zap logger")
	})
}

type wrapper struct {
	L *zap.Logger
	F []zap.Field
}

func Field(field map[string]interface{}) *wrapper {
	var fds, i = make([]zap.Field, len(field)), 0
	for key, fv := range field {
		switch fv.(type) {
		case int:
			fds[i] = zap.Int(key, fv.(int))
		case string:
			fds[i] = zap.String(key, fv.(string))
		case float64:
			fds[i] = zap.Float64(key, fv.(float64))
		case interface{}:
			fds[i] = zap.Any(key, fv)
		default:
			panic(errors.New("unknow field"))
		}
		i++
	}

	return &wrapper{
		L: logger,
		F: fds,
	}
}

func (r *wrapper) Field(field map[string]interface{}) *wrapper {
	var fds, i = make([]zap.Field, len(field)), 0
	for key, fv := range field {
		switch fv.(type) {
		case int:
			fds[i] = zap.Int(key, fv.(int))
		case string:
			fds[i] = zap.String(key, fv.(string))
		case float64:
			fds[i] = zap.Float64(key, fv.(float64))
		case interface{}:
			fds[i] = zap.Any(key, fv)
		default:
			r.L.Fatal("unknow field type", r.F...)
		}
		i++
	}
	r.F = append(r.F, fds...)
	return r
}

func (r wrapper) Debugf(format string, args ...interface{}) {
	if r.L == nil {
		r.L, _ = zap.NewProduction()
		defer r.L.Sync()
		r.L.Debug(fmt.Sprintf(format, args))
	} else {
		r.L.Debug(fmt.Sprintf(format, args))
	}
}

func (r wrapper) Infof(format string, args ...interface{}) {

	if r.L == nil {
		r.L, _ = zap.NewProduction()
		defer r.L.Sync()
		r.L.Info(fmt.Sprintf(format, args))
	} else {
		r.L.Info(fmt.Sprintf(format, args))
	}
}

func (r wrapper) Warnf(format string, args ...interface{}) {
	if r.L == nil {
		r.L, _ = zap.NewProduction()
		defer r.L.Sync()
		r.L.Warn(fmt.Sprintf(format, args))
	} else {
		r.L.Warn(fmt.Sprintf(format, args))
	}
}

func (r wrapper) Errorf(format string, args ...interface{}) {
	if r.L == nil {
		r.L, _ = zap.NewProduction()
		defer r.L.Sync()
		r.L.Error(fmt.Sprintf(format, args))
	} else {
		r.L.Error(fmt.Sprintf(format, args))
	}
}

func (r wrapper) Fatalf(format string, args ...interface{}) {
	if r.L == nil {
		r.L, _ = zap.NewProduction()
		defer r.L.Sync()
		r.L.Fatal(fmt.Sprintf(format, args))
	} else {
		r.L.Fatal(fmt.Sprintf(format, args))
	}
}

func Debugf(format string, args ...interface{}) {
	if logger == nil {
		log, _ := zap.NewProduction()
		//log:= zap.NewExample()
		defer log.Sync()
		log.Debug(fmt.Sprintf(format, args))
	} else {
		logger.Debug(format, zap.Reflect(format, args))
	}
}

func Infof(format string, args ...interface{}) {
	if logger == nil {
		log, _ := zap.NewProduction()
		defer log.Sync()
		log.Info(fmt.Sprintf(format, args))
	} else {
		logger.Info(fmt.Sprintf(format, args))
	}
}

func Warnf(format string, args ...interface{}) {

	if logger == nil {
		log, _ := zap.NewProduction()
		defer log.Sync()
		log.Warn(fmt.Sprintf(format, args))
	} else {
		logger.Warn(fmt.Sprintf(format, args))
	}
}

func Errorf(format string, args ...interface{}) {

	if logger == nil {
		log, _ := zap.NewProduction()
		defer log.Sync()
		log.Error(fmt.Sprintf(format, args))
	} else {
		logger.Error(fmt.Sprintf(format, args))
	}
}

func Fatalf(format string, args ...interface{}) {
	if logger == nil {
		log, _ := zap.NewProduction()
		defer log.Sync()
		log.Fatal(fmt.Sprintf(format, args))
	} else {
		logger.Fatal(fmt.Sprintf(format, args))
	}
}
